package org.cocos2d.utils;

import java.io.ByteArrayOutputStream;
import java.io.FileInputStream;
import java.io.FileNotFoundException;
import java.io.IOException;
import java.nio.ByteBuffer;
import java.nio.ByteOrder;
import java.nio.FloatBuffer;
import java.nio.ShortBuffer;

import javax.microedition.khronos.opengles.GL10;

public class BufferProvider {
    // 64k is big enough for most objects
    private static final int ALLOCATION_SIZE = 1024 * 1024;
    private static BufferProvider global_synced = new BufferProvider();
    private ByteBuffer currentBuffer = null;

    public static ByteBuffer allocateDirect(int size) {
        synchronized (global_synced) {
            return global_synced.allocate(size);
        }
    }

    public static void drawQuads(GL10 gl, FloatBuffer fbVert, FloatBuffer fbCoord) {
        fbVert.position(0);
        fbCoord.position(0);

        gl.glEnableClientState(GL10.GL_VERTEX_ARRAY);
        gl.glEnableClientState(GL10.GL_TEXTURE_COORD_ARRAY);
        gl.glVertexPointer(3, GL10.GL_FLOAT, 0, fbVert);
        gl.glTexCoordPointer(2, GL10.GL_FLOAT, 0, fbCoord);
        gl.glDrawArrays(GL10.GL_TRIANGLE_STRIP, 0, 4);
        gl.glDisableClientState(GL10.GL_TEXTURE_COORD_ARRAY);
        gl.glDisableClientState(GL10.GL_VERTEX_ARRAY);

    }

    public static void fillFloatBuffer(FloatBuffer fb, float[] arr) {
        fb.position(0);
        fb.put(arr);
    }

    public static FloatBuffer makeFloatBuffer(float[] arr) {
        ByteBuffer bb = BufferProvider.allocateDirect(arr.length * 4);
        bb.order(ByteOrder.nativeOrder());
        FloatBuffer fb = bb.asFloatBuffer();
        fb.put(arr);
        fb.position(0);
        return fb;
    }

    public static FloatBuffer createFloatBuffer(int arrayElementCount) {
        ByteBuffer temp = BufferProvider.allocateDirect(4 * arrayElementCount);
        temp.order(ByteOrder.nativeOrder());

        return temp.asFloatBuffer();
    }

    public static ByteBuffer createByteBuffer(int arrayElementCount) {
        ByteBuffer temp = BufferProvider.allocateDirect(arrayElementCount);
        temp.order(ByteOrder.nativeOrder());

        return temp;
    }

    public static ShortBuffer createShortBuffer(int arrayElementCount) {
        ByteBuffer temp = BufferProvider.allocateDirect(2 * arrayElementCount);
        temp.order(ByteOrder.nativeOrder());

        return temp.asShortBuffer();
    }

    public static ByteBuffer bufferFromFile(String path) {
        ByteArrayOutputStream tmpOut = new ByteArrayOutputStream();
        byte[] buf = new byte[1024];
        int len = 0;
        try {
            FileInputStream fis = new FileInputStream(path);
            while (true) {
                len = fis.read(buf);
                if (len == -1)
                    break;
                tmpOut.write(buf, 0, len);
            }
        } catch (FileNotFoundException e) {
            // TODO Auto-generated catch block
            e.printStackTrace();
        } catch (IOException e) {
            // TODO Auto-generated catch block
            e.printStackTrace();
        }

        ByteBuffer bb = ByteBuffer.wrap(tmpOut.toByteArray());
        return bb;
    }

    public ByteBuffer allocate(int size) {
        if (size >= ALLOCATION_SIZE)
            return ByteBuffer.allocateDirect(size);

        if (currentBuffer == null || size > currentBuffer.remaining())
            currentBuffer = ByteBuffer.allocateDirect(ALLOCATION_SIZE);

        currentBuffer.limit(currentBuffer.position() + size);
        ByteBuffer result = currentBuffer.slice();

        currentBuffer.position(currentBuffer.limit());
        currentBuffer.limit(currentBuffer.capacity());
        return result;
    }
}
